# Copyright (c) 2024, hzmes and contributors
# For license information, please see license.txt


from ast import If
from webbrowser import get
import frappe
from frappe.core.doctype.user.user import User
from frappe.model.document import Document
from frappe.permissions import add_user_permission
import requests
import json
from frappe import _, format_value, get_doc, msgprint
from frappe.utils import now, add_to_date, get_date_str, today, validate_email_address, cint, date_diff
import datetime
from hzplm.hz_plm.erp_sync import K3CloudSync


class ServerConfig(Document):
    pass
    # def validate(self):
    #     if self.disable == 0:
    #         num = frappe.db.count('Server Config', {'disable': 0})
    #         if num > 1:
    #             frappe.throw('为了数据准确,只允许有一个在启用的服务器配置!请禁用之前的配置!')


# 从ERP同步物料
@frappe.whitelist()
def sync_material_from_erp():
    doc_name = frappe.db.get_all("ERP Sync Config",filters={'fname': '同步物料主数据', 'enable': 1},fields=['name'])
    # 增加一个if判断,避免sync = K3CloudSync(doc_name[0].name)时 IndexError: list index out of range
    if doc_name:
        sync = K3CloudSync(doc_name[0].name)
        sync.sync()


# 从ERP同步采购订单
@frappe.whitelist()
def sync_po_from_erp():
    doc_name = frappe.db.get_list(
        "ERP Sync Config",
        filters={'fname': '采购订单', 'enable': 1},
        fields=['name'], ignore_permissions=True
    )
    # 增加一个if判断,避免sync = K3CloudSync(doc_name[0].name)时 IndexError: list index out of range
    if doc_name:
        sync = K3CloudSync(doc_name[0].name)
        sync.sync()


# 登录验证:校验服务器配置是否有效
@frappe.whitelist()
def login_validate(server_url, acctid, user_name, user_password): 
    # login_url 是登录函数的URL,
    login_url = server_url + "Kingdee.BOS.WebApi.ServicesStub.AuthService.ValidateUser.common.kdsvc"
	# 构建登录接口的传参
    login_data={"acctid": acctid, "username": user_name, "password":user_password ,"lcid": 2052}
    # 验证URL及参数
    # frappe.msgprint(f'the login_data is {login_data}')
    login_response = requests.post(url=login_url, data=login_data)
    return login_response.json()["Message"] if login_response.json()["Message"] else 'OK'


# 登录并且返回cookies
@frappe.whitelist()
def login_k3cloud(server_url, acctid, user_name, user_password):
    login_url = server_url + "Kingdee.BOS.WebApi.ServicesStub.AuthService.ValidateUser.common.kdsvc"
    login_data={"acctid": acctid, "username": user_name, "password":user_password ,"lcid": 2052}
    login_response = requests.post(url=login_url, data=login_data)
    if login_response.json()["LoginResultType"] == 1:
        # 返回cookies
        return login_response.cookies
    # return login_response


# 增加计量单位
@frappe.whitelist()
def add_uom_from_erp(uom_name):
    doc = frappe.get_doc({'doctype':'SRM UOM' , 'uom_name': uom_name})
    doc.insert()


# 增加物料组
@frappe.whitelist()
def add_material_group_from_erp(material_group, parent_group=None):       
    doc = frappe.get_doc({'doctype':'SRM Material Group' , 'material_group': material_group, 'parent_srm_material_group': parent_group})
    doc.insert()

# 创建K3Cloud项目主数据
@frappe.whitelist()
def create_to_k3cloud_project(docname, orgid='100'):
    # 从server_config中获取server_url, acctid, user_name, user_password
    project = frappe.get_doc('Project', docname)
    # 2025-05-08修订: project_formid从系统配置上获取,不再是写死的ID
    project_formid = frappe.get_doc('API Option', '83u24e57m1').formid
    server_config = frappe.db.get_all('Server Config', filters = {'disable': 0, 'sync_system': 'k3clound'}, fields = ['server_url', 'user_name', 'acctid', 'user_password'])
    if len(server_config) > 0:
        login_response = login_k3cloud(server_config[0].server_url, server_config[0].acctid, server_config[0].user_name, server_config[0].user_password)
        # 调用登录函数
        if login_response:
            # 构建保存接口URL
            save_url = server_config[0].server_url + "Kingdee.BOS.WebApi.ServicesStub.DynamicFormService.Save.common.kdsvc"
            # 构建k3Cloud的传参参数，其中{}是从API中复制得来
            post_options = {
                            "Model": {
                                "FID": 0,
                                "FNumber": project.name,   # 项目编号
                                "FCreateOrgId": {"FNumber": orgid}, # 创建组织
                                "FUseOrgId": {"FNumber": orgid},    # 使用组织
                                "FName": project.project_name,    # 项目名称
                                "F_THLH_Combo": "1" if project.custom_product_type == '扩板' else "2" if project.custom_product_type == '膜片' else "3",     # 产品类型: 1扩板,2膜片,3复合
                            }
            }
            # 序列化json.dumps()
            post_data = { "FormID": project_formid, "Data": json.dumps(post_options) }
            # 同步至K3cloud生成项目主数据
            save_response = requests.post(url = save_url, data = post_data, cookies = login_response)
            r = json.loads(save_response.text)
            if r["Result"]["ResponseStatus"]["IsSuccess"] == True:
                # 从ERP返回ID保存起来
                custom_erp_fid = r["Result"]["Id"]
                project.custom_erp_fid = custom_erp_fid
                project.save()
                return custom_erp_fid
            else:
                frappe.msgprint(r["Result"]["ResponseStatus"]["Errors"][0]["Message"])


# 同步项目状态至K3Cloud项目主数据
@frappe.whitelist()
def sync_to_k3cloud_project_status(docname):
    # 从server_config中获取server_url, acctid, user_name, user_password
    project = frappe.get_doc('Project', docname)
    project_formid = frappe.get_doc('API Option', '83u24e57m1').formid
    if project.custom_erp_fid > 0 and project_formid:
        server_config = frappe.db.get_all('Server Config', filters = {'disable': 0, 'sync_system': 'k3clound'}, fields = ['server_url', 'user_name', 'acctid', 'user_password'])
        if len(server_config) > 0:
            login_response = login_k3cloud(server_config[0].server_url, server_config[0].acctid, server_config[0].user_name, server_config[0].user_password)
            # 调用登录函数
            if login_response:
                # 构建保存接口URL
                save_url = server_config[0].server_url + "Kingdee.BOS.WebApi.ServicesStub.DynamicFormService.Save.common.kdsvc"
                # 构建k3Cloud的传参参数，其中{}是从API中复制得来
                post_options = { "Model": {"FID": project.custom_erp_fid,"FDescription": project.custom_current_schedule,} }
                # 序列化json.dumps()
                post_data = { "FormID": project_formid, "Data": json.dumps(post_options) }
                # 同步至K3cloud生成项目主数据
                save_response = requests.post(url = save_url, data = post_data, cookies = login_response)
                r = json.loads(save_response.text)
                if r["Result"]["ResponseStatus"]["IsSuccess"] == True:
                    # 从ERP返回ID保存起来
                    return r["Result"]["Id"]
                else:
                    frappe.msgprint(r["Result"]["ResponseStatus"]["Errors"][0]["Message"])


# 获取会计凭证GL_VOUCHER
@frappe.whitelist()
def get_gl_voucher_from_erp(date_from, date_to, startrow):
    server_config = frappe.db.get_all('Server Config', filters = {'disable': 0, 'sync_system': 'k3clound'}, fields = ['server_url', 'user_name', 'acctid', 'user_password'])
    if len(server_config) > 0:
        login_response = login_k3cloud(server_config[0].server_url, server_config[0].acctid, server_config[0].user_name, server_config[0].user_password)

    if login_response:
        query_url = server_config[0].server_url + "Kingdee.BOS.WebApi.ServicesStub.DynamicFormService.ExecuteBillQuery.common.kdsvc"
        op = frappe.get_doc('API Option', 'hg2e4p012i') #指定参数取值
        exclude_expense = tuple(op.exclude_expense.split(","))
        account_fnumber = tuple(op.account.split(","))
        
        post_options = {"data": json.dumps({
            "FormId": "GL_VOUCHER",
            "FieldKeys": "FDate,FAccountBookID.FName,FVOUCHERGROUPID.FName,FVOUCHERGROUPNO,FEXPLANATION,FACCOUNTID.FNumber,FAcctFullName,FDetailID.FFLEX9.FNumber,FDetailID.FFLEX9.FName, FDetailID.FF100006.FNumber,FAmount, FEntity_FEntryID, FYEAR, FPERIOD, FSourceBillKey.FName, FSystemID.FName ",
            # FDetailID.FF100003.FNumber != '' # 研发项目不为空
            # FPOSTERID>0 AND FDC=1 # 已过账并且是借方发生额
            # FDetailID.FFLEX9.FNumber not in {exclude_expense} # 排除可能会重复导凭证的费用项目
            # FACCOUNTID.FNumber='{account_fnumber}' # 科目代码
            "FilterString": f" FDetailID.FF100006.FNumber != '' AND FPOSTERID>0 AND FDC=1 AND FDate>='{date_from}' AND FDate<='{date_to}' AND FDetailID.FFLEX9.FNumber not in {exclude_expense} AND FACCOUNTID.FNumber in {account_fnumber} ",
            "OrderString": "FVOUCHERGROUPNO",
            "StartRow": startrow,
            "Limit": 2000,
            })
        }
        query_response = requests.post(url=query_url, data=post_options, cookies=login_response)
        # 将json格式数据转换为字典,获取入库明细
        res = json.loads(query_response.text)
        return res


@frappe.whitelist()
def all_get_gl_voucher_from_erp(date_from, date_to):
    # 计算日期范围天数不超过31天
    day_diff = date_diff(date_to, date_from)
    if day_diff>31:frappe.throw('为了接口稳定,日期范围不能超过1个月!')
    # 判断日期范围内是否已经有凭证,避免重复
    v = frappe.db.get_all('GL Voucher Allocation', filters=[['date', 'between', [date_from, date_to]]])
    if len(v)>0:frappe.throw('日期范围内已经有总账凭证,请先删除再取数!')
    # 初始化起始行为0
    startrow = 0
    # 初始化接收列表为空
    vouchers = []
    # 循环:2万条内
    while startrow < 20000:
        # 获取limit:2000条返回行
        r = get_gl_voucher_from_erp(date_from, date_to, startrow)
        # 判断有返回由往接收列表中抛并且把起始行变量+2000(为什么是+2000,跟limit匹配)
        if r and len(r) > 0:
            for i in r:
                vouchers.append(i)
            startrow += 2000
        # 如果没有返回则跳出循环
        else:
            break
    if len(vouchers)>0:
        for item in vouchers:
            voucher = frappe.get_doc({'doctype': 'GL Voucher Allocation', 'date': item[0], 'accountbook': item[1], 'vouchergroup_name': item[2], 'vouchergroup_no': item[3], 'explanation': item[4], 'account_fnumber': item[5], 'acctfullname': item[6], 'detail_expense_number': item[7], 'detail_expense_name': item[8], 'detail_project_number': item[9], 'amount': item[10], 'fentity_fentryid': item[11], 'year': item[12], 'fperiod': item[13], 'fsourcebill': item[14], 'fsystem': item[15]})
            voucher.insert()
    return vouchers


# 获取折旧分配表FA_DeprDistribute
@frappe.whitelist()
def get_fa_deprdistribute_from_erp(fyear, fperiod):
    server_config = frappe.db.get_all('Server Config', filters = {'disable': 0, 'sync_system': 'k3clound'}, fields = ['server_url', 'user_name', 'acctid', 'user_password'])
    if len(server_config) > 0:
        login_response = login_k3cloud(server_config[0].server_url, server_config[0].acctid, server_config[0].user_name, server_config[0].user_password)

    if login_response:
        query_url = server_config[0].server_url + "Kingdee.BOS.WebApi.ServicesStub.DynamicFormService.GetSysReportData.common.kdsvc"
        # 注意: 从报表取数时格式有些变化, FormID在data外围
        post_options = {"FormId": "FA_DeprDistribute","data": json.dumps(
                {
                "FieldKeys": "FCostItem,FCardNumber,FAssetName,FCostAmount",
                "IsVerifyBaseDataField": "true",
                "Model": {
                    "FAcctpolicy": "1",
                    "FYearStart": fyear,
                    "FYearEnd": fyear,
                    "FPeriodStart": fperiod,
                    "FPeriodEnd": fperiod,
                    "FUseDeptStart": { "FNumber": "06"},
                    "FUseDeptEnd": {"FNumber": "06"},
                    "FShowDetails": 1,
                    "FGatherType": "1",
                    "FAcctOrg": "1_1",
                    "FAssetOrg": "1",
                    "FOwnerOrg": "1"
                }
                })
        }
        query_response = requests.post(url=query_url, data=post_options, cookies=login_response)
        res = json.loads(query_response.text)
        if res["Result"]["IsSuccess"] == True:
            return res["Result"]["Rows"]
  
# 获取其他出库单get_misdelivery_from_erp
@frappe.whitelist()
def get_misdelivery_from_erp(date_from, date_to, dept_number='06'):
    # 计算日期范围天数不超过31天
    day_diff = date_diff(date_to, date_from)
    if day_diff>31:frappe.throw('为了接口稳定,日期范围不能超过1个月!')
    # 判断日期范围内是否已经有凭证,避免重复
    v = frappe.db.get_all('Stock Entry', filters=[['posting_date', 'between', [date_from, date_to]], ['stock_entry_type', '=', 'Material Issue']])
    if len(v)>0:frappe.throw('日期范围内已经有其他出库单,请先删除再取数!')

    server_config = frappe.db.get_all('Server Config', filters = {'disable': 0, 'sync_system': 'k3clound'}, fields = ['server_url', 'user_name', 'acctid', 'user_password'])
    if len(server_config) > 0:
        login_response = login_k3cloud(server_config[0].server_url, server_config[0].acctid, server_config[0].user_name, server_config[0].user_password)

    if login_response:
        query_url = server_config[0].server_url + "Kingdee.BOS.WebApi.ServicesStub.DynamicFormService.ExecuteBillQuery.common.kdsvc"
        
        post_options = {"data": json.dumps(
                {   "FormId": "STK_MisDelivery",
                    "FieldKeys": "FBillNo, FStockDirect, FStockOrgId.FName, FDate, FDeptId.FName, F_THLH_Base.FNumber, FMaterialId.FNumber, FMaterialName, FUnitID.FName, FQty, FPrice, FAmount, FModel ",
                    "FilterString": f" FDate>='{date_from}' AND FDate<='{date_to}' AND FDeptId.FNumber='{dept_number}' AND F_THLH_Base>0 ",
                    "Limit": 2000,
                })
        }
        # print(post_options)
        query_response = requests.post(url=query_url, data=post_options, cookies=login_response)
        # 将json格式数据转换为字典,获取入库明细
        r = json.loads(query_response.text)
        if len(r) > 0:
            # 检查是否有不存在的计量单位UOM
            uoms = []
            for i in r:uoms.append(i[8])
            for uom in list(set(uoms)):
                if not frappe.db.exists({"doctype": "UOM", "name": uom}):
                    frappe.get_doc({ "doctype": "UOM", "uom_name": uom }).insert()
            # 检查有不存在的物料并更新成本单价
            for i in r:
                if not frappe.db.exists({"doctype": "Item", "name": i[6]}):
                    frappe.get_doc({"doctype": "Item", "item_code": i[6], "item_name": i[7], "stock_uom": i[8], "valuation_rate": i[10]}).insert()
                else:
                    doc = frappe.get_doc("Item", i[6])
                    doc.valuation_rate = i[10]
                    doc.save()
            # 到这里,UOM和Item都补全了,可以同步写入其他出库单
            # 1 先初始化一个my_dict, 空dict
            my_dict = {}
            # 2 拼装my_dict
            for i in r: # 遍历ERP返回的list结果集
                cur_key = i[0] # key赋值
                # 判断当前cur_key是否在my_dict中
                if cur_key in my_dict:
                    my_dict[cur_key]["items"].append({ "s_warehouse": "K原料仓 - R","item_code": i[6],"qty": i[9] })
                # 如果cur_key不在my_dict, 并且是库存方向是普通的, 则添加元素, 以单据号为key
                elif i[1] == 'GENERAL':
                    my_dict[cur_key] = {"doctype": "Stock Entry", "stock_entry_type": "Material Issue", "purpose": "Material Issue", "posting_date": i[3], "custom_fbillno": i[0], "project": i[5], "custom_erp_info": i[4]+i[5], "set_posting_time": 1, "items": [{"s_warehouse": "K原料仓 - R", "item_code": i[6], "qty": i[9]}]}
            # 3 遍历my_dict, 写入其他出库单
            for key in my_dict: doc = frappe.get_doc(my_dict[key]).insert()
            return r
        else:
            frappe.throw(f'从日期{date_from}至日期{date_to}没有符合条件的数据可同步!')
        
# 获取其他出库单get_misdelivery_from_erp1
@frappe.whitelist()
def get_misdelivery_from_erp1(date_from, date_to, dept_number='06'):
    # 计算日期范围天数不超过31天
    day_diff = date_diff(date_to, date_from)
    if day_diff>31:frappe.throw('为了接口稳定,日期范围不能超过1个月!')
    # 判断日期范围内是否已经有凭证,避免重复
    v = frappe.db.get_all('Miscellaneous Delivery', filters=[['date', 'between', [date_from, date_to]]])
    if len(v)>0:frappe.throw('日期范围内已经有其他出库单,请先删除再取数!')

    server_config = frappe.db.get_all('Server Config', filters = {'disable': 0, 'sync_system': 'k3clound'}, fields = ['server_url', 'user_name', 'acctid', 'user_password'])
    if len(server_config) > 0:
        login_response = login_k3cloud(server_config[0].server_url, server_config[0].acctid, server_config[0].user_name, server_config[0].user_password)

    if login_response:
        query_url = server_config[0].server_url + "Kingdee.BOS.WebApi.ServicesStub.DynamicFormService.ExecuteBillQuery.common.kdsvc"
        # 2025-05-08优化: 增加同步F_THLH_cklx.FDataValue出库类型
        # 2025-05-19优化: 改造FieldKeys,实现动态扩展erp_info字段的同步
        init_fieldkeys = "FBillNo, FStockDirect, FStockOrgId.FName, FDate, FDeptId.FName, F_THLH_Base.FNumber, FMaterialId.FNumber, FMaterialName, FUnitID.FName, FQty, FPrice, FAmount, FModel,"
        more_fieldkeys = ""
        if frappe.db.exists('API Option', {'type': '其他出库-ERP信息'}):
            more_fieldkeys = frappe.db.get_value('API Option', {'type': '其他出库-ERP信息'}, ['chuku_erp_info'])
        post_options = {"data": json.dumps(
                {   "FormId": "STK_MisDelivery",
                    "FieldKeys": init_fieldkeys + more_fieldkeys,   #2025-05-19优化:动态字段配置
                    "FilterString": f" FDate>='{date_from}' AND FDate<='{date_to}' AND FDeptId.FNumber='{dept_number}' AND F_THLH_Base>0 ",
                    "Limit": 2000,
                })
        }
        # print(post_options)
        query_response = requests.post(url=query_url, data=post_options, cookies=login_response)
        # 将json格式数据转换为字典,获取入库明细
        r = json.loads(query_response.text)
        if len(r) > 0:
            # 检查是否有不存在的计量单位UOM
            uoms = []
            for i in r:uoms.append(i[8])
            for uom in list(set(uoms)):
                if not frappe.db.exists({"doctype": "UOM", "name": uom}):
                    frappe.get_doc({ "doctype": "UOM", "uom_name": uom }).insert()
            # 检查有不存在的物料并更新成本单价
            for i in r:
                if not frappe.db.exists({"doctype": "Item", "name": i[6]}):
                    frappe.get_doc({"doctype": "Item", "item_code": i[6], "item_name": i[7], "stock_uom": i[8], "valuation_rate": i[10], "description": i[12]}).insert()
                else:
                    doc = frappe.get_doc("Item", i[6])
                    doc.valuation_rate = i[10]
                    doc.save()
            # 到这里,UOM和Item都补全了,可以同步写入其他出库单
            # 1 先初始化一个my_dict, 空dict
            my_dict = {}
            # 2 拼装my_dict
            for i in r: # 遍历ERP返回的list结果集
                # 2025-05-19优化: 因为是动态扩展字段,此处计算出r结果的返回字段长度
                max_index = len(i)
                min_index = 13
                erp_info = ""
                # 2025-05-19优化: 拼装erp_info(理论上后续扩展的同步字段信息都拼装在erp_info字段上)
                while min_index < max_index:
                    erp_info = erp_info + i[min_index] + '/'
                    min_index += 1
                cur_key = i[0] # key赋值
                # 判断当前cur_key是否在my_dict中
                if cur_key in my_dict:
                    my_dict[cur_key]["items"].append({ "s_warehouse": "K原料仓 - R","item_code": i[6],"qty": i[9], "valuation_rate": i[10], "amount": i[11] })
                # 如果cur_key不在my_dict, 并且是库存方向是普通的, 则添加元素, 以单据号为key
                elif i[1] == 'GENERAL':
                    my_dict[cur_key] = {"doctype": "Miscellaneous Delivery", "date": i[3], "fbillno": i[0], "project": i[5], "erp_info": erp_info, "stockdirect": "GENERAL", "items": [{"s_warehouse": "K原料仓 - R", "item_code": i[6], "qty": i[9], "valuation_rate": i[10], "amount": i[11] }]}
                elif i[1] != 'GENERAL':
                    my_dict[cur_key] = {"doctype": "Miscellaneous Delivery", "date": i[3], "fbillno": i[0], "project": i[5], "erp_info": erp_info, "stockdirect": "RETURN", "items": [{"s_warehouse": "K原料仓 - R", "item_code": i[6], "qty": i[9], "valuation_rate": i[10], "amount": i[11] }]}
            # 3 遍历my_dict, 写入其他出库单
            for key in my_dict: doc = frappe.get_doc(my_dict[key]).insert()
            return r
        else:
            frappe.throw(f'从日期{date_from}至日期{date_to}没有符合条件的数据可同步!')
        
# 获取其他入库单get_miscellaneous_from_erp1
@frappe.whitelist()
def get_miscellaneous_from_erp1(date_from, date_to, dept_number='06'):
    # 计算日期范围天数不超过31天
    day_diff = date_diff(date_to, date_from)
    if day_diff>31: frappe.throw('为了接口稳定,日期范围不能超过1个月!')
    # 判断日期范围内是否已经有凭证,避免重复
    v = frappe.db.get_all('Miscellaneous Receipt', filters=[['date', 'between', [date_from, date_to]] ])
    if len(v)>0: frappe.throw('日期范围内已经有其他入库单,请先删除再取数!')

    server_config = frappe.db.get_all('Server Config', filters = {'disable': 0, 'sync_system': 'k3clound'}, fields = ['server_url', 'user_name', 'acctid', 'user_password'])
    if len(server_config) > 0:
        login_response = login_k3cloud(server_config[0].server_url, server_config[0].acctid, server_config[0].user_name, server_config[0].user_password)

    if login_response:
        query_url = server_config[0].server_url + "Kingdee.BOS.WebApi.ServicesStub.DynamicFormService.ExecuteBillQuery.common.kdsvc"
        # 2025-05-08优化: 增加同步F_THLH_rklx.FDataValue入库类型
        # 2025-05-19优化: 改造FieldKeys,实现动态扩展erp_info字段的同步
        init_fieldkeys = "FBillNo, FStockDirect, FStockOrgId.FName, FDate, FDeptId.FName, F_THLH_Base.FNumber, FMaterialId.FNumber, FMaterialName, FUnitID.FName, FQty, FPrice, FAmount, FModel, FSTOCKID.FName,"
        more_fieldkeys = ""
        if frappe.db.exists('API Option', {'type': '其他入库-ERP信息'}):
            more_fieldkeys = frappe.db.get_value('API Option', {'type': '其他入库-ERP信息'}, ['ruku_erp_info'])
        post_options = {"data": json.dumps(
                {
                    "FormId": "STK_MISCELLANEOUS",  #其他入库
                    "FieldKeys": init_fieldkeys + more_fieldkeys,   #动态字段配置
                    "FilterString": f" FDate>='{date_from}' AND FDate<='{date_to}' AND FDeptId.FNumber={dept_number} AND F_THLH_Base>0 ",
                    "Limit": 2000,
                })
        }
        # print(post_options)
        query_response = requests.post(url=query_url, data=post_options, cookies=login_response)
        # 将json格式数据转换为字典,获取入库明细
        r = json.loads(query_response.text)
        if len(r) > 0:
            # print(r)    # 20250519调试
            # 检查是否有不存在的计量单位UOM
            uoms = []
            for i in r:uoms.append(i[8])
            for uom in list(set(uoms)):
                if not frappe.db.exists({"doctype": "UOM", "name": uom}):
                    frappe.get_doc({ "doctype": "UOM", "uom_name": uom }).insert()
            # 检查有不存在的物料并更新成本单价
            for i in r:
                if not frappe.db.exists({"doctype": "Item", "name": i[6]}):
                    frappe.get_doc({"doctype": "Item", "item_code": i[6], "item_name": i[7], "stock_uom": i[8], "valuation_rate": i[10], "description": i[12] }).insert()
                else:
                    doc = frappe.get_doc("Item", i[6])
                    doc.valuation_rate = i[10]
                    doc.save()
            # 到这里,UOM和Item都补全了,可以同步写入其他出库单
            # 1 先初始化一个my_dict, 空dict
            my_dict = {}
            # 2 拼装my_dict
            for i in r: # 遍历ERP返回的list结果集
                # 2025-05-19优化: 因为是动态扩展字段,此处计算出r结果的返回字段长度
                max_index = len(i)
                min_index = 14
                erp_info = ""
                # 2025-05-19优化: 拼装erp_info(理论上后续扩展的同步字段信息都拼装在erp_info字段上)
                while min_index < max_index:
                    erp_info = erp_info + i[min_index] + '/'
                    min_index += 1
                cur_key = i[0] # key赋值
                # 判断当前cur_key是否在my_dict中
                if cur_key in my_dict:
                    my_dict[cur_key]["receipt_items"].append({ "t_warehouse": "K原料仓 - R","item_code": i[6],"qty": i[9], "valuation_rate": i[10], "amount": i[11]  })
                # 如果cur_key不在my_dict, 并且是库存方向是普通的, 则添加元素, 以单据号为key
                elif i[1] == 'GENERAL':
                    my_dict[cur_key] = {"doctype": "Miscellaneous Receipt", "date": i[3], "fbillno": i[0], "project": i[5], "erp_info": erp_info, "stockdirect": "GENERAL", "receipt_items": [{"t_warehouse": "K原料仓 - R", "item_code": i[6], "qty": i[9], "valuation_rate": i[10], "amount": i[11] }]}
                elif i[1] != 'GENERAL':
                    my_dict[cur_key] = {"doctype": "Miscellaneous Receipt", "date": i[3], "fbillno": i[0], "project": i[5], "erp_info": erp_info, "stockdirect": "RETURN", "receipt_items": [{"t_warehouse": "K原料仓 - R", "item_code": i[6], "qty": i[9], "valuation_rate": i[10], "amount": i[11] }]}
            
            # 3 遍历my_dict, 写入其他入库单
            for key in my_dict: doc = frappe.get_doc(my_dict[key]).insert()
            return r
        else:
            frappe.throw(f'从日期{date_from}至日期{date_to}没有符合条件的数据可同步!')


@frappe.whitelist()
def my_requests(query_url, post_options, login_response):
    # pass
    query_response = requests.post(url=query_url, data=post_options, cookies=login_response)
    # 将json格式数据转换为字典
    res = json.loads(query_response.text)
    return res

@frappe.whitelist()
def my_requests1(query_url, post_options):
    # pass
    query_response = requests.post(url=query_url, data=post_options)
    # 将json格式数据转换为字典
    res = json.loads(query_response.text)
    return res


# 从HR同步考勤记录,每天同步前一天的考勤
@frappe.whitelist()
def sync_hr_data_day():
    server_url = frappe.db.get_all('Server Config', filters = {'disable': 0, 'sync_system': 'hr'}, fields = ['server_url'])   
    if server_url:
        query_url = server_url[0]['server_url']  # 查询api接口地址
        oneday = add_to_date(today(), days=-1)  # 前一天日期
        post_options = {"bd": oneday, "ed": oneday} # 构造传叁
        res = my_requests1(query_url, post_options) # 调用api查询返回结果res
        if res:
            for item in res["data"]:
                # 用res元素中的EmpNo查找是否有员工档案
                emp = frappe.db.get_all('Employee', filters = {'custom_empno': item['EmpNo']})
                if emp: # 已经有员工档案,直接写入考勤记录
                    frappe.get_doc({'doctype': 'Attendance', 'employee': emp, 'working_hours': item['WorkTimes'], 'attendance_date': oneday}).insert()
                else:   # 没有员工档案,先写入员工再写入考勤记录
                    new_emp = frappe.get_doc({'doctype':'Employee','custom_empno': item['EmpNo'], 'first_name': item['EmpCName'], 'gender': 'Male', 'date_of_birth': '2000-01-01', 'date_of_joining': '2000-01-01'})
                    new_emp.insert()
                    frappe.get_doc({'doctype': 'Attendance', 'employee': new_emp.name, 'working_hours': item['WorkTimes'], 'attendance_date': oneday}).insert()
    else:
        pass

